import defineReactive from "./defineReactive.js";
import Dep from "./dep.js";
// 初始化数据 具体的方法实现
function initData(vm) {
  const { data } = vm.$options;
  // data 就是我们在首页 new Vue({data(){return {}}})  的data
  // console.log('data ==> ', data);
  let _data;
  if (data) {
    // 把data的值挂载到vm实例上
    // data 有可能是个闭包方法 所以要判断如果是闭包执行以下获取一下里面的json
    _data = vm._data = typeof data === "function" ? data() : data;
  }
  // console.log('_data ===> ', _data);
  for (const key in _data) {
    // 把data数据代理到 _data 下 是他支持 this.xxx 调用
    // 原理 当我们调用 this.xxx 时,会把我们的指向为 this._data.xxx
    // props methods computed同理
    proxyDataToVm(vm, "_data", key);
  }
  // 设置完代理以后 给data数据设置响应式更新
  observe(vm._data);
}

// 响应式判断和设置响应式
function observe(data) {
  // 需要对数据defineProperty 进行重新观测
  // 只对对象类型进行观测，非对象类型无法观测
  if (typeof data !== "object" || data == null) return;
  // 如果已经被观察过
  if (data.__ob__) return value.__ob__;
  return new Observer(data);
}

function Observer(data) {
  // 给每个数据都加上一个 __ob__ 属性 表示已经处理了响应式拦截和更新
  Object.defineProperty(data, "__ob__", {
    value: this,
    // 数据可枚举
    enumerable: false,
    // 数据可修改
    writable: true,
    // 数据可配置
    configurable: true,
  });
  // console.log("data ==> ", data);
  // 对值进行依赖收集
  data.__ob__.dep = new Dep();
  // 给对象的每一项都设置响应式
  window.$keyert++;
  this.walk(data);
}

window.$keyert = 0;
// 给对象属性设置响应式 (只支持对象)
Observer.prototype.walk = function (obj) {
  for (let key in obj) {
    // 依次给对象设置拦截
    if (typeof obj[key] === "object") {
      observe(obj[key]);
    } else {
      defineReactive(obj, key, obj[key]);
    }
  }
};

// 挂载Data到实例Vm
function proxyDataToVm(target, sourceKey, key) {
  // 代理 当访问指定targert对象时 例：Obj.a 代理到 Obj.data.a
  Object.defineProperty(target, key, {
    get() {
      return target[sourceKey][key];
    },
    set(val) {
      debugger;
      target[sourceKey][key] = val;
    },
  });
}

export default initData;
